/*
Copyright (C) 2015 Marien Raat

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <fractalNoise.h>
#include <normalizer.h>

FractalNoiseGenerator::FractalNoiseGenerator(std::mt19937 *mt)
{
    perlinNoiseGenerator = new PerlinNoiseGenerator(mt);
    firstNoiseMap = true;
}

FractalNoiseGenerator::~FractalNoiseGenerator()
{
    delete perlinNoiseGenerator;
}

void FractalNoiseGenerator::generateStandardFractalNoise(
    unsigned width,
    unsigned height,
    double powerFeatureSizeMultiplier,
    unsigned smallestFeatureSize,
    bool overwriteOldMap)
{
    if (firstNoiseMap || !overwriteOldMap) {
        noiseMap = new double[width * height];
    } else if (width != previousWidth || height != previousHeight) {
        delete noiseMap;
        noiseMap = new double[width * height];
    }

    firstNoiseMap = false;
    previousWidth = width;
    previousHeight = height;

    for (unsigned i = 0; i < width * height; i++) noiseMap[i] = 0.0;
    
    unsigned smallestSide = std::min(width, height);
    unsigned currentFeatureSize = smallestSide;

    while (currentFeatureSize >= smallestFeatureSize) {
        double *currentPerlinMap = perlinNoiseGenerator->
            generatePerlinNoiseMap(width, height, currentFeatureSize);

        for (unsigned i = 0; i < width * height; i++)
            noiseMap[i] += currentPerlinMap[i] *
                pow((double) currentFeatureSize,
                    powerFeatureSizeMultiplier);
        
        currentFeatureSize /= 2;
        if ((width % currentFeatureSize) != 0 ||
            (height % currentFeatureSize) != 0)
            break;
    }
}

void FractalNoiseGenerator::generateFractalNoiseFromValues(
    double *values,
    unsigned ammountOfValues,
    unsigned width,
    unsigned height,
    bool overwriteOldMap)
{
    if (firstNoiseMap || !overwriteOldMap) {
        noiseMap = new double[width * height];
    } else if (width != previousWidth || height != previousHeight) {
        delete noiseMap;
        noiseMap = new double[width * height];
    }

    firstNoiseMap = false;
    previousWidth = width;
    previousHeight = height;

    for (unsigned i = 0; i < width * height; i++) noiseMap[i] = 0.0;
    
    for (int i = 0; i < ammountOfValues; i += 2) {
        double *currentPerlinMap = perlinNoiseGenerator->
            generatePerlinNoiseMap(width, height, values[i]);

        Normalizer<double>::normalize(currentPerlinMap, currentPerlinMap,
                                      width * height, -1.0, 1.0);

        for (unsigned j = 0; j < width * height; j++)
            noiseMap[j] += currentPerlinMap[j] * values[i + 1];
    }
}
